package com.jintian.smart.kernel.flowable.component.action.flow;

import com.jintian.smart.kernel.common.util.StringUtil;
import com.jintian.smart.kernel.core.auth.IOperator;
import com.jintian.smart.kernel.core.flow.FlowAction;
import com.jintian.smart.kernel.flowable.common.utils.BeanUtils;
import com.jintian.smart.kernel.flowable.component.action.base.AbstractFlowAction;
import com.jintian.smart.kernel.flowable.context.DefaultProcessContext;
import com.jintian.smart.kernel.flowable.domain.entity.ActHiTaskInst;
import com.jintian.smart.kernel.flowable.domain.view.FlowBizVo;
import com.jintian.smart.kernel.flowable.listener.FlowEventListenerManager;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.DelegationState;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Component
public class QueryFlowAction extends AbstractFlowAction<FlowBizVo> {
    @Override
    public FlowAction getAction() {
        return FlowAction.query;
    }

    @Autowired
    private FlowEventListenerManager flowEventListenerManager;

    @Override
    protected FlowBizVo innerExecute(String bizId, String bizClass, String process) throws Exception {
        try (DefaultProcessContext context = (DefaultProcessContext) this.processContextProvider.createInstance(process, null, this.getAction(),
                null, null, bizId, null);) {
            flowEventListenerManager.triggerBeforeListener(context.getProcess(), context.getActivity(), context.getAction(), context);
            FlowBizVo result = QueryFlow(bizId, bizClass, context.getProcess());
            flowEventListenerManager.triggerAfterListener(context.getProcess(), context.getActivity(), context.getAction(), context);
            return result;
        } finally {
            flowEventListenerManager.unbindProcessContext(process, null, this.getAction());
        }
    }

    private FlowBizVo QueryFlow(String bizId, String bizClass, String process) {
        FlowBizVo flowBizVo = new FlowBizVo();
        HistoricProcessInstanceQuery query = this.historyService().createHistoricProcessInstanceQuery().processInstanceBusinessKey(bizId);
        if (StringUtil.isNoneBlank(process)) {
            query = query.processDefinitionKey(process);
        }
        if (StringUtil.isNoneBlank(bizClass)) {
            query = query.variableValueEquals(FlowAction.VARNAME_START_BIZCLASS, bizClass);
        }
        List<HistoricProcessInstance> list = query.orderByProcessInstanceStartTime().desc().list();
        if (list.size() > 1) {
            throw new FlowableException("当前业务存在多个流程实例，请指定流程id");
        }
        HistoricProcessInstance pi = list.size() == 1 ? list.get(0) : null;
        if (pi != null) {
            IOperator checkIOperator = FlowAction.getFlowOwner();
            List<TaskEntity> taskList = this.findPrincipalTaskList(pi.getId(), checkIOperator);
            flowBizVo.setId(pi.getId());
            flowBizVo.setProcess(pi.getProcessDefinitionKey());
            flowBizVo.setProcessLabel(pi.getName());
            if (pi.getEndTime() != null) {
                flowBizVo.setFinished(true);
                ProcessInstance activeInstance = this.runtimeService().createProcessInstanceQuery().processInstanceId(pi.getId()).singleResult();
                if (activeInstance != null) {
                    flowBizVo.setFinished(activeInstance.isSuspended());
                }
            }
            if (taskList != null) {
                flowBizVo.setOwnTasks(BeanUtils.copyList(taskList.stream().filter(t -> !DelegationState.PENDING.equals(t.getDelegationState())).collect(Collectors.toList()), ActHiTaskInst.class));
            }
        }
        return flowBizVo;
    }
}
